package com.quest.space.poker.biz.impl;

import com.alibaba.fastjson.JSON;
import com.quest.space.data.WebSocketMsg;
import com.quest.space.poker.base.bean.TableException;
import com.quest.space.poker.base.enums.PokerRoleEnum;
import com.quest.space.poker.base.enums.PokerTypeEnum;
import com.quest.space.poker.base.utils.PokerUtil;
import com.quest.space.poker.base.utils.SnowFlake;
import com.quest.space.poker.biz.GameService;
import com.quest.space.poker.biz.PokerService;
import com.quest.space.poker.dto.PlayerDto;
import com.quest.space.poker.dto.PokerDto;
import com.quest.space.poker.dto.TableDto;
import com.quest.space.websocket.LocalMessageHandler;
import io.opentelemetry.api.internal.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.quest.space.poker.base.bean.PokerConstants.PASS;
import static com.quest.space.poker.base.bean.PokerConstants.bottom;
import static com.quest.space.poker.base.utils.PokerUtil.printTable;
import static com.quest.space.poker.biz.impl.TableServiceImpl.*;

public class GameServiceImpl implements GameService {
    private static PokerService pokerService = new PokerServiceImpl();

    @Override
    public void joinGame(PlayerDto player) {
        //初始化一局人机游戏
        TableDto table = createRobotTable(player);
        //洗牌
        List<List<PokerDto>> pokers = pokerService.getPokers();
        Map<String, List<PokerDto>> map = new HashMap<>();
        map.put(bottom, pokers.get(0));
        int index = 1;
        //发牌
        for (PlayerDto p : table.getPlayers()) {
            map.put(p.getPlayerId(), pokers.get(index));
            index++;
        }
        table.setPokers(map);
        //默认用户为地主,，后面可随机
        String playerId = player.getPlayerId();
        table.setLandlord(playerId);
        for (PlayerDto p : table.getPlayers()) {
            if (p.getPlayerId().equals(playerId)) {
                p.setType(PokerRoleEnum.LANDLOARD.getValue());
            }else {
                p.setType(PokerRoleEnum.FARMER.getValue());
            }
        }
        //将底牌给地主
        map.get(playerId).addAll(map.get(bottom));
        //排序
        map.put(playerId, map.get(playerId).stream()
                .sorted(Comparator.comparingInt(PokerDto::getValue))
                .collect(Collectors.toList()));
        //将桌面信息发给用户
        WebSocketMsg msg = new WebSocketMsg();
        printTable(table);
        msg.setData(JSON.toJSONString(table));
        LocalMessageHandler.handleServerMsg(msg);
    }

    @Override
    public void handle(WebSocketMsg msgVo) {
        String input = msgVo.getData().toString();
        System.out.println("玩家出牌：" + input);
        TableDto table = getTable(msgVo.getTableId());
        String playerId = msgVo.getFrom();
        if(!input.equals(PASS)){
            handleUser(input, table, playerId);
        }
        //人机局，电脑自动出牌
        if (table.isRobot()) {
            PlayerDto player = table.getPlayer(playerId);
            PlayerDto robot = player.getNext();
            pokerService.handleRobot(table, robot, player);
        }
    }

    private void handleUser(String poker, TableDto table, String playerId) {
        List<PokerDto> pokerList = PokerUtil.sortPokerStr(poker);
        List<PokerDto> allPokers = table.getAllPokers(playerId);
        //获取牌型
        PokerTypeEnum pokerType = PokerTypeEnum.getPokerType(poker);
        System.out.println("当前牌型：" + pokerType.getDesc());
        String prePoker = table.getPrePoker();
        List<PokerDto> prePokerList = table.getPrePokerList();
        PokerTypeEnum prePokerType = table.getPrePokerType();
        //当前牌桌为第一次出牌或者上一手出牌人为自己时，不需要判断当前牌，直接出
        boolean check = !StringUtils.isNullOrEmpty(prePoker);
        if(playerId.equals(table.getPrePlayer())) {
            check = false;
        }
        //比较与上一手牌型的大小
        if (check) {
            //先比较牌型是否一致
            System.out.println("table-> preplayer:" + table.getPrePlayer() + " preType: " + table.getPrePokerType().getDesc());
            if (!comparePokerType(pokerType, prePokerType)) {
                throw new TableException("牌型不符合规则: " + pokerType, playerId);
            }
            //再比较大小，比较总值大小
            if (!comparePokerValue(poker, prePoker, pokerList, prePokerList, pokerType)) {
                throw new TableException("大小不符合规则", playerId);
            }
        }
        //将玩家当前所出的牌从剩余的牌中移除
        PokerUtil.remove(pokerList, allPokers, table, playerId);
        //如果最终牌为空，则判定游戏结束
        if (CollectionUtils.isEmpty(table.getAllPokers(playerId))) {
            WebSocketMsg msg = new WebSocketMsg();
            table.setOver(true);
            table.setWinner(playerId);
            printTable(table);
            msg.setData(JSON.toJSONString(table));
            LocalMessageHandler.handleServerMsg(msg);
            return;
        }

        table.setPrePoker(poker);
        table.setPrePokerList(pokerList);
        table.setPrePlayer(playerId);
        table.setPrePokerType(pokerType);
        table.setShowPokers(playerId, poker);

        table.setAction(1);
        WebSocketMsg msg = new WebSocketMsg();
        System.out.println("玩家出牌：" +poker);
        printTable(table);
        msg.setData(JSON.toJSONString(table));
        LocalMessageHandler.handleServerMsg(msg);

    }

    private boolean comparePokerType(PokerTypeEnum current, PokerTypeEnum old) {
        //先判断当前牌是否为炸弹
        if (current.equals(PokerTypeEnum.BOMB)) {
            return true;
        } else {
            return current.equals(old);
        }
    }

    private boolean comparePokerValue(String poker, String oldPoker, List<PokerDto> currentList, List<PokerDto> oldList, PokerTypeEnum pokerType) {
        if (poker.equals("wW")) {//王炸直接返回
            return true;
        }
        return PokerUtil.compare(currentList, oldList, poker, oldPoker, pokerType);
    }

    private TableDto createRobotTable(PlayerDto player) {
        TableDto tableDto = new TableDto();
        String tableId = SnowFlake.nextId();
        tableDto.setTableName(player.getName() + "'s game");
        tableDto.setTableId(tableId);
        List<PlayerDto> players = new ArrayList<>();
        players.add(player);
        //添加两个机器人
        PlayerDto p1 = createRobot("1");
        players.add(p1);
        PlayerDto p2 = createRobot("2");
        players.add(p2);
        tableDto.setPlayers(players);
        tableDto.setStartDate(new Date());
        tableDto.setPlayerNum(3);
        tableDto.setRobot(true);

        //设置每个玩家的出牌顺序，设置成一个环
        player.setNext(p1);
        p1.setNext(p2);
        p2.setNext(player);
        putTable(tableDto);
        return tableDto;
    }

    private PlayerDto createRobot(String id) {
        PlayerDto robot = new PlayerDto();
        robot.setPlayerId(id);
        robot.setRobot(true);
        robot.setName("player-" + id);
        return robot;
    }


}
